#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <string.h>

using namespace std;

/*********** 硬件异常产生信号 a.除0访问 b.野指针异常 *********/
// 异常是不应该被修正的，因为代码就不应该出异常，所以一般的异常处理机制都是让进程中断运行，或者打印一些信息，这样才能让程序员知道代码出问题了。
// 为什么异常是属于硬件异常呢，明明是代码的问题，不应该是软件吗？
// 其实是软硬件结合的，首先代码会编译形成而形成二进制文件，每一句代码都会在cpu的执行，是放到了cpu的寄存器上的，当产生异常的时候，首先是寄存器发现的，所以称硬件异常，然后cpu把os叫过来，由os操作系统处理异常，os就会去找进程，（即发送对应信号给进程）问他怎么出错了，然后进程发现出错就直接中断退出
// void handler(int signo)
// {
//     cout << "get a sig, number is : " << signo << endl;
//     exit(-1);
// }
// int main()
// {
//     // a. 除0异常     8号
//     // signal(SIGFPE, handler);
//     // int a = 10;
//     // a /= 0;

//     // b.野指针异常  11号
//     signal(SIGSEGV, handler);
//     int* p = nullptr;
//     *p = 100;

//     return 0;
// }

/*********** 软件条件产生信号 a.管道 b.alarm函数和SIGALRM : 14信号 *********/
// int g_cnt = 0;
// int ret = 0;
// void handler(int signo)
// {
//     ret = alarm(0);
//     // cout << "get a sig, number is : " << signo << endl;
//     cout << "上一个闹钟剩余时间 ： " <<  "ret = " << ret << endl;
//     // cout << "g_cnt = " << g_cnt << endl;
//     exit(1);
// }
// int main()
// {
//     // 为了看到 n 即 alarm函数的返回值，则执行了alarm函数不能直接中断进程，所以用signal函数自定义获取信号后的处理方法
//     signal(SIGALRM, handler);

//     // alarm特点
//     // 1、默认处理方法是倒计时结束直接中断进程
//     // 2、闹钟只响一次
//     // 3、要想响多次，就用signal来自定义闹钟处理函数，在其里面添加一个闹钟，这样一个闹钟响了就会触发下一个闹钟
//     // 4、返回值是上一个设定的闹钟还剩余的时间
//     // 5、alarm(0) 不是立即响，而是取消闹钟

//     // 由于我使用的是xsell远程连接云服务器，打印需要访问硬件（显示器），所以很慢，而且需要通过网络传输数据和指令，这是主要原因
//     alarm(1);
//     int cnt = 0;
//     while (true)
//     {
//         cout << "cnt:" << cnt++ << ", pid :" << getpid() << endl;
//         // sleep(1);
//     }
//     // 对比上面，cnt只能加到两万左右，g_cnt能跑到五亿左右的数字，可以看出内存级比访问IO的速度快的是万级别
//     // alarm(1);
//     // cout << "pid :" << getpid() << endl;
//     // while (true)
//     // {
//     //     g_cnt++; // 纯内存级
//     // }
//     return 0;
// }

/***********           raise和abort函数接口产生信号           *********/
// void handler(int signo)
// {
//     cout << "get a sig, number is : " << signo << endl;
// }
// int main()
// {
//     signal(2, handler);
//     int cnt = 0;
//     while (true)
//     {
//         cout << "cnt:" << cnt++ << endl;
//         sleep(1);
//         if (cnt % 5 == 0)
//         {
//             /*
//             RAISE(3)   3号手册
//             raise - send a signal to the caller
//             #include <signal.h>
//             int raise(int sig);           <===> 等价于 kill(getpid(), sig);
//             The raise() function sends a signal to the calling process or thread.  In
//             a single-threaded program it is equivalent to
//             */
//             // cout << " send 2 to caller" << endl;
//             // raise(2); // SIGSTOP : 19

//             /*
//             abort - cause abnormal process termination
//             #include <stdlib.h>      SIGABRT : 6号 信号
//             void abort(void);   <===> 等价于  kill(getpid(), SIGABRT);
//             */
//             // cout << " send SIGABRT to caller" << endl;
//             // abort();
//         }
//     }
//     return 0;
// }

/************     kill系统调用接口产生信号     *********/
// int main(int argc, char *argv[])
// {
//     if (argc != 3)
//     {
//         cout << "Usage : " << argv[0] << " -signumber pid" << endl;
//         return 1;
//     }
//     // stoi用于把字符串转换成为整数 argv[1] 一般是输入的 -2 或者 -9 再或者 -SIGINT这种，所以第一个是-，第二个才是信号
//     int signumber = stoi(argv[1] + 1);
//     int pid = stoi(argv[2]);
//     /*  kill - send signal to a process
//         #include <sys/types.h>
//         #include <signal.h>
//         kill 用于发送sig信号给给pid进程，返回值小于0说明发送失败
//         int kill(pid_t pid, int sig);*/
//     int n = kill(pid, signumber);
//     if (n < 0)
//     {
//         cerr << "kill error, " << strerror(errno) << endl;
//     }

//     return 0;
// }

/***********          signal系统调用接口的使用           *********/
// void handler(int signo)
// {
//     cout << "get a sig, number is : " << signo << endl;
// }

// int main()
// {
//     // signal 是系统调用接口 用于设置自定义处理指定信号的handler方法
//     /*
//         #include <signal.h>
//         // 这是一个函数指针，sighandler_t为该函数指针的类型，这个类型定义出来的都是函数指针，即传函数名，在其内部用于回调，来使用该函数
//         typedef void (*sighandler_t)(int);
//         // 返回值是原来调用的函数指针（一般是信号触发的默认处理方法）
//         sighandler_t signal(int signum, sighandler_t handler);
//     */
//     // signal调用完了，handler方法会被立即执行吗？不是，只是设置对应信号的处理方法
//     // 未来进程收到了该信号才执行handler方法
//     signal(SIGINT, handler);

//     while (true)
//     {
//         cout << "I am activing..., pid: " << getpid() << endl;
//         sleep(1);
//     }

//     return 0;
// }
